/**
 * \file  therapy.h
 * \brief Definition of TherapyNode and Therapy class.
 *
 * ASO: Antiviral Sequence Optimizer
 * <http://aso.googlecode.com/>
 * Copyright (C) 2010 Velez Ezequiel, Peralta Andres, FuDePAN
 *
 * This file is part of the ASO project.
 *
 * Contents:       Header file for ASO providing classes TherapyNode and Therapy.
 *
 * System:         ASO
 * Language:       C++
 *
 * Author:         Velez Ezequiel, Peralta Andres
 * E-Mail:
 *
 * ASO is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * ASO is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with ASO.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

#ifndef THERAPY_H
#define THERAPY_H

#include <mili/mili.h>
#include "aso-core/common_types.h"
#include "aso-core/combinatory_policy.h"
#include "aso-core/antiviral_set.h"


/*! Informacion adicional a un nodo */
struct Info
{
    virtual const std::string& get_info() const = 0;
};

/*! Definicion de la clase TherapyNode */
class TherapyNode
{
protected:
    typedef std::list<TherapyNode*> ChildrenList;
    typedef mili::AutonomousIterator<ChildrenList>  ChildrenIterator;

    const size_t id;                       //! identificador único
    TherapyNode* parent;                   //! puntero a nodo padre
    Info* info;                            //! info extra del nodo
    CombinatoryPolicy* combPolicy;         //! politica combinatoria

public:
    typedef mili::CAutonomousIterator<ChildrenList> ConstChildrenIterator;

    const biopp::PseudoNucSequence sequence;         //! secuencia de la mutante que representa
    AntiviralSet antivirals;            //! conjunto de antivirales
    const DistanceValue value;          //! distancia entre mutanciones

    /*! Constructor */
    TherapyNode(const biopp::PseudoNucSequence& sequence, TherapyNode* parent, const AntiviralSet& av, DistanceValue value, const size_t id, CombinatoryPolicy* comb)
        : id(id),
          parent(parent),
          info(NULL),
          combPolicy(comb),
          sequence(sequence),
          antivirals(av),
          value(value)
    {}

    /*! Constructor de copia */
    TherapyNode(const TherapyNode& other)
        : id(other.id),
          parent(other.parent),
          info(NULL),
          combPolicy(other.combPolicy),
          sequence(other.sequence),
          antivirals(other.antivirals),
          value(other.value)
    {}

    ~TherapyNode()
    {}

    /*! Operador de Equivalencia */
    inline bool operator==(const TherapyNode& other) const
    {
        return id == other.id;
    }

    /*! Obtener el id */
    inline size_t get_id() const
    {
        return id;
    }

    /*! Es nodo hoja? */
    //bool is_leaf() const;

    /*! Es nodo raiz? */
    bool is_root() const;

    /*! Obtener un nodo padre */
    inline TherapyNode* get_parent() const
    {
        return parent;
    }

    /*! Asignar un nodo padre */
    inline void set_parent(TherapyNode* newParent)
    {
        parent = newParent;
    }

    /*! Asignar informacion extra en el nodo */
    inline void set_info(Info* infoNode)
    {
        info = infoNode;
    }

    /*! Obtener informacion extra del nodo */
    inline const std::string& get_info()
    {
        return info->get_info();
    }

    /*! Retorna la politica combinatoria a aplicar */
    inline CombinatoryPolicy* get_combination_policy() const
    {
        return combPolicy;
    }

    inline void set_combination_policy(CombinatoryPolicy* comb)
    {
        combPolicy = comb;
    }

    /* Retorna un clon del therapy node que lo invoca */
    virtual TherapyNode* clone() const = 0;
    /* Función que asigna puntaje a las terapias */
    virtual Score scoring() const = 0;
    /* Retorna true si la terapia se debe continuar, false de otro modo */
    virtual TherapyStatus continue_therapy() const = 0;
    /* Permite cambiar el combinador de AV en caso de fallo virologico */
    virtual CombinatoryPolicy* virologic_failure(const CombinationStatus& status) = 0;
};

/*! Definicion de la Clase Therapy*/
class Therapy : public std::list<TherapyNode*>
{
public:
    /*! Constructor */
    Therapy(TherapyNode* last_node)
    {
        const TherapyNode* aux = last_node;
        while (aux != NULL)
        {
            TherapyNode* aux2 = aux->clone();
            if (!empty())
            {
                TherapyNode* aux3 = front();
                aux3->set_parent(aux2);
            }
            push_front(aux2);
            aux = aux->get_parent();
        }
    }
    /*! Destructor */
    ~Therapy()
    {
        mili::delete_container(static_cast<std::list<TherapyNode*>&>(*this));
    }

    /*! Operador de Equivalencia */
    inline bool operator==(const Therapy& other) const
    {
        mili::CAutonomousIterator<Therapy> otherit(other);
        mili::CAutonomousIterator<Therapy> thisit(*this);
        bool equal(true);

        if (other.size() == this->size())
        {
            while (!otherit.end() && equal)
            {
                equal = (*otherit)->antivirals == (*thisit)->antivirals;
                ++otherit;
                ++thisit;
            }
        }
        else
            equal = false;
        return equal;
    }

    /*! Imprimir una terapia */
    void get_antivital_names(std::string& output) const;
};

//! iterador constante de terapias.
typedef mili::CAutonomousIterator<Therapy> TherapyIterator;

#endif
